// 版权所有20092010 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// NetBSD系统调用。
// 该文件编译为普通Go代码，
// 但它也是mksyscall的输入，
// 解析
// 请注意，有时我们使用小写
// syscall_bsd.go或syscall_unix.go中。

package syscall

import "unsafe"

type SockaddrDatalink struct {
	Len    uint8
	Family uint8
	Index  uint16
	Type   uint8
	Nlen   uint8
	Alen   uint8
	Slen   uint8
	Data   [12]int8
	raw    RawSockaddrDatalink
}

func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)

func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) {
	var olen uintptr

	// 通过执行
	// 附加CTL_查询的给定MIB的sysctl，获取给定MIB下所有sysctl节点的列表。
	mib = append(mib, CTL_QUERY)
	qnode := Sysctlnode{Flags: SYSCTL_VERS_1}
	qp := (*byte)(unsafe.Pointer(&qnode))
	sz := unsafe.Sizeof(qnode)
	if err = sysctl(mib, nil, &olen, qp, sz); err != nil {
		return nil, err
	}

	// 现在我们知道了大小，得到了实际的节点。
	nodes = make([]Sysctlnode, olen/sz)
	np := (*byte)(unsafe.Pointer(&nodes[0]))
	if err = sysctl(mib, np, &olen, qp, sz); err != nil {
		return nil, err
	}

	return nodes, nil
}

func nametomib(name string) (mib []_C_int, err error) {
	// 将名称拆分为组件。
	var parts []string
	last := 0
	for i := 0; i < len(name); i++ {
		if name[i] == '.' {
			parts = append(parts, name[last:i])
			last = i + 1
		}
	}
	parts = append(parts, name[last:])

	// 发现节点并构造MIB OID。
	for partno, part := range parts {
		nodes, err := sysctlNodes(mib)
		if err != nil {
			return nil, err
		}
		for _, node := range nodes {
			n := make([]byte, 0)
			for i := range node.Name {
				if node.Name[i] != 0 {
					n = append(n, byte(node.Name[i]))
				}
			}
			if string(n) == part {
				mib = append(mib, _C_int(node.Num))
				break
			}
		}
		if len(mib) != partno+1 {
			return nil, EINVAL
		}
	}

	return mib, nil
}

func direntIno(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
}

func direntReclen(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
}

func direntNamlen(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}

func Pipe(p []int) (err error) {
	return Pipe2(p, 0)
}

// sysnb pipe2（p*[2]\u C_int，flags int）（错误）
func Pipe2(p []int, flags int) error {
	if len(p) != 2 {
		return EINVAL
	}
	var pp [2]_C_int
	err := pipe2(&pp, flags)
	p[0] = int(pp[0])
	p[1] = int(pp[1])
	return err
}

// sys paccept（fd int，rsa*RawSockaddrAny，addrlen*\u Socklen，sigmask*sigset，flags int）（nfd int，error error）
func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	nfd, err = paccept(fd, &rsa, &len, nil, flags)
	if err != nil {
		return
	}
	if len > SizeofSockaddrAny {
		panic("RawSockaddrAny too small")
	}
	sa, err = anyToSockaddr(&rsa)
	if err != nil {
		Close(nfd)
		nfd = 0
	}
	return
}

func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
	return getdents(fd, buf)
}

// TODO，参见golang.org/issue/5847 
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
	return -1, ENOSYS
}

func setattrlistTimes(path string, times []Timespec) error {
	// 在达尔文上使用的UtimesNano 
	return ENOSYS
}

/*
 * Exposed directly
 */
// sys Access（路径字符串，模式uint32）（错误）
// sys Adjtime（delta*Timeval，olddta*Timeval）（错误）
// sys Chdir（路径字符串）（错误）
// sys Chflags（路径字符串，标志int）（错误）
// sys Chmod（路径字符串，模式uint32）（错误）
// sys Chown（路径字符串，uid int，gid int）（错误）
// sys Chroot（路径字符串）（错误）
// sysnb Getpgid（pid int）（pgid int，error error）
// sysnb Getpgrp（）（pgrp int）
// sysnb Getpid（）（pid int）
// sysnb Getppid（）（ppid int）
// sys Getpriority（which int，who int）（prio int，error）
// sys Kqueue（）（fd int，error）
// sys Lchown（path string，uid int，gid int）（error）
// sys Link（path string，Link string）（error error）
// sys Listen（s int，backlog int）（error）
// sys Mkdir（路径字符串，模式uint32）（err error）
// sys Mkfifo（路径字符串，模式uint32）（err error）
// sys Mknod（路径字符串，模式uint32，开发内部）（err err err err）
// sys NANOEP（时间*时间段，剩余*时间段）（err err err err）
// sys Open（路径字符串，模式int，perm uint32）（fd int，error error）
// sys Pathconf（路径字符串，名称int）（val int，error error）
// sys Pread（fd int，p[]byte，offset int64）（n int，error）
// sys Pwrite（fd int，p[]byte，offset int64）（n int，error）
// sys Readlink（路径字符串，buf[]字节）（n int，error error）
// sys Rename（从字符串到字符串）（errr error）
// sys Revoke（路径字符串）（error error error）
// sys Seek（fd int，offset int64，whence int）（newoffset int64，error error）=SYS_LSEEK 
// SYS Select（n int，r*FdSet，w*FdSet，e*FdSet，timeout*Timeval）（error error）
// sysnb Setegid（egid int）（error error）
// sysnb Seteuid（euid int）（error）
// sysnb Setgid（gid int）（error）
// sys Setpriority（which int，who int，prio int）（error error）
// sysnb Setregid（rgid int，egid int）（error error）
// sysnb Setreuid（ruid int，euid int）（error error error）
// sysnb Setrlimit（which int，lim*Rlimit）（error error）
// sysnb setid（）（pid int，error error）
// sysnb Settimeofday（tp*Timeval）（错误）
// sysnb Setuid（uid int）（错误）
// sys Stat（path string，Stat*Stat\t）（error）
// sys Symlink（path string，link string）（error）
// sys Sync（）（error）
// sys Truncate（路径字符串，长度int64）（错误）
// sys Umask（newmask int）（oldmak int）
// sys Unlink（路径字符串）（错误）
// sys Unmount（路径字符串，标志int）（错误）
// sys write（fd int，p[]字节）（n int，错误）
// sys munmap（addr uintpttr，length uintptpr）（error error）
// sys readlen（fd int，buf*byte，nbuf int）（n int，error error）=sys READ 
// sys writelen（fd int，buf*byte，nbuf int，nbuf int，nbuf int）=SYS\u WRITE 
// SYS utimensat（dirfd int，path string，times*[2]Timespec，flag int）（错误）
// SYS getcwd（buf[]byte）（n int，error error）=SYS
